#include "BomItemParser.h"

#include "BomCategoryParser.h"
#include "BomDesParser.h"
#include "CharacteristicsParser.h"
#include "IntParser.h"
#include "QStringParser.h"

#include <QXmlStreamReader>
#include <QString>

namespace Ipc2581b
{

BomItemParser::BomItemParser(
    QStringParser *&_oEMDesignNumberRefParser
    , QStringParser *&_quantityParser
    , IntParser *&_pinCountParser
    , BomCategoryParser *&_categoryParser
    , QStringParser *&_internalPartNumberParser
    , QStringParser *&_descriptionParser
    , BomDesParser *&_bomDesParser
    , CharacteristicsParser *&_characteristicsParser
):    m_oEMDesignNumberRefParser(_oEMDesignNumberRefParser)
    , m_quantityParser(_quantityParser)
    , m_pinCountParser(_pinCountParser)
    , m_categoryParser(_categoryParser)
    , m_internalPartNumberParser(_internalPartNumberParser)
    , m_descriptionParser(_descriptionParser)
    , m_bomDesParser(_bomDesParser)
    , m_characteristicsParser(_characteristicsParser)
{

}

bool BomItemParser::parse(QXmlStreamReader *reader)
{
    /* Pre */

    m_result.reset(new BomItem());

    /* Attributes */

    QStringRef data;
    if (reader->attributes().hasAttribute(QStringLiteral("OEMDesignNumberRef")))
    {
        data = reader->attributes().value(QStringLiteral("OEMDesignNumberRef"));
        if (!m_oEMDesignNumberRefParser->parse(reader, data))
            return false;
        m_result->oEMDesignNumberRef = m_oEMDesignNumberRefParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("OEMDesignNumberRef: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("quantity")))
    {
        data = reader->attributes().value(QStringLiteral("quantity"));
        if (!m_quantityParser->parse(reader, data))
            return false;
        m_result->quantity = m_quantityParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("quantity: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("pinCount")))
    {
        data = reader->attributes().value(QStringLiteral("pinCount"));
        if (!m_pinCountParser->parse(reader, data))
            return false;
        m_result->pinCountOptional = Optional<Int>(m_pinCountParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("category")))
    {
        data = reader->attributes().value(QStringLiteral("category"));
        if (!m_categoryParser->parse(reader, data))
            return false;
        m_result->category = m_categoryParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("category: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("internalPartNumber")))
    {
        data = reader->attributes().value(QStringLiteral("internalPartNumber"));
        if (!m_internalPartNumberParser->parse(reader, data))
            return false;
        m_result->internalPartNumberOptional = Optional<QString>(m_internalPartNumberParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("description")))
    {
        data = reader->attributes().value(QStringLiteral("description"));
        if (!m_descriptionParser->parse(reader, data))
            return false;
        m_result->descriptionOptional = Optional<QString>(m_descriptionParser->result());
    }

    /* Elements */

    while (reader->readNextStartElement())
    {
        auto name = reader->name();
        if (m_bomDesParser->isSubstitution(name))
        {
            if (!m_bomDesParser->parse(reader))
                return false;
            auto result = m_bomDesParser->result();
            m_result->bomDesList.append(result);
        }
        else if (name == QStringLiteral("Characteristics"))
        {
            if (!m_characteristicsParser->parse(reader))
                return false;
            auto result = m_characteristicsParser->result();
            m_result->characteristics = result;
        }
        else
            reader->skipCurrentElement();
    }

    /* Post */

    // TODO: Check multiplicity of elements/attributes

    return true;
}

BomItem *BomItemParser::result()
{
    return m_result.take();
}

}